home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / SOURCES / ASM / STACK.ASM < prev    next >
Encoding:
Assembly Source File  |  1993-10-14  |  54.0 KB  |  1,687 lines

  1. ;* STACK.ASM
  2. ;************************************************************************
  3. ;*                                    *
  4. ;*        PC Scheme/Geneva 4.00 Borland TASM code            *
  5. ;*                                    *
  6. ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT        *
  7. ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva    *
  8. ;*                                    *
  9. ;*----------------------------------------------------------------------*
  10. ;*                                    *
  11. ;*    All that concern the stack (push, pop, execute, return)        *
  12. ;*            (interpreter support)                *
  13. ;*                                    *
  14. ;*----------------------------------------------------------------------*
  15. ;*                                    *
  16. ;* Created by: John Jensen        Date: 1985            *
  17. ;* Revision history:                            *
  18. ;* - 18 Jun 92:    Renaissance (Borland Compilers, ...)            *
  19. ;*                                    *
  20. ;*                    ``In nomine omnipotentii dei''    *
  21. ;************************************************************************
  22. IDEAL
  23. %PAGESIZE    60, 132
  24. MODEL    small
  25. LOCALS    @@
  26.  
  27.     INCLUDE    "scheme.ash"
  28.     INCLUDE "interprt.ash"
  29.  
  30. DATASEG
  31.  
  32. stk_in    DD    0            ; number of bytes moved into the stack
  33. stk_out    DD    0            ; number of bytes moved out of the stack
  34.  
  35. CODESEG
  36.  
  37. ;************************************************************************
  38. ;*                                al    *
  39. ;* Push register onto stack                PUSH    reg    *
  40. ;*                                    *
  41. ;* Purpose:    Interpreter support to cause the contents of one of the    *
  42. ;*    VM's general registers to be pushed onto the VM's        *
  43. ;*    runtime stack                            *
  44. ;************************************************************************
  45. PROC    spush
  46.     get1op
  47. @@retry:
  48.     mov    di, [topofstack]
  49.     cmp    di, STKSIZE-SIZE POINTER; test for overflow
  50.     jge    @@overflow
  51.     add    di, SIZE POINTER    ; decrement stack top pointer
  52.     mov    [topofstack], di
  53.     mov    bx, ax            ; copy register number
  54.     mov    ax, [regs+bx.page]
  55.     mov    [(POINTER s_stack+di).page], al
  56.     mov    ax, [regs+bx.disp]
  57.     mov    [(POINTER s_stack+di).disp], ax
  58.     jmp    next
  59. @@overflow:                ; process stack overflow-- copy contents to heap
  60.     push    ax            ; preserve "important" regs across call
  61.     call    stk_ovfl C        ; handle overflow situation
  62.     pop    ax
  63.     mov    bx, [cb_reg.page]
  64.     ldpage    es, bx
  65.     jmp    @@retry
  66. ENDP    spush
  67.  
  68. ;************************************************************************
  69. ;*                                al    *
  70. ;* Pop register from stack                POP    reg    *
  71. ;*                                    *
  72. ;* Purpose:    Interpreter support to cause the contents of one of the    *
  73. ;*    VM's general registers to be replaced by popping the        *
  74. ;*    value off the top of the VM's runtime stack            *
  75. ;*                                    *
  76. ;* Note: There's no need to check for stack underflow on a simple    *
  77. ;*    POP, because the stack is broken into segments only at stack    *
  78. ;*    frame boundaries. Underflow can occur only when stack space    *
  79. ;*    for a stack frame is released (i.e., during an EXIT).        *
  80. ;************************************************************************
  81. PROC    spop
  82.     get1op
  83.     mov    di, [topofstack]
  84.     mov    bx, ax            ; copy register number
  85.     mov    al, [(POINTER s_stack+di).page]
  86.     mov    [regs+bx.page], ax
  87.     mov    ax, [(POINTER s_stack+di).disp]
  88.     mov    [regs+bx.disp], ax
  89.     sub    di, SIZE POINTER    ; decrement topofstack pointer
  90.     mov    [topofstack], di
  91.     jmp    next
  92. ENDP    spop
  93.  
  94. ;************************************************************************
  95. ;*                                al    *
  96. ;* Drop-- remove top elements from stack        DROP    n    *
  97. ;*                                    *
  98. ;* Purpose: Interpreter support to cause the top "n" elements of the    *
  99. ;*    VM's runtime stack to be discarded. "n" is determined        *
  100. ;*    from the operand of the DROP instruction            *
  101. ;*                                    *
  102. ;* Note: There's no need to check for stack underflow on a DROP        *
  103. ;*    because the stack is broken into segments only at stack        *
  104. ;*    frame boundaries. Underflow can occur only when stack space    *
  105. ;*    for a stack frame is released (i.e., during an EXIT).        *
  106. ;************************************************************************
  107. PROC    sdrop
  108.     get1op
  109.     mov    dx, ax            ; multiply by 3 (size of element)
  110.     shl    ax, 1
  111.     add    ax, dx
  112.     sub    [topofstack], ax
  113.     jmp    next
  114. ENDP    sdrop
  115.  
  116. ;************************************************************************
  117. ;*                            al    ah    *
  118. ;* Local from local stack frame            LDLOCAL dest,    entry    *
  119. ;************************************************************************
  120. PROC    ld_local
  121.     get2op
  122.     mov    bl, al            ; copy destination register number
  123.     mov    di, bx            ;    into di (clear high order BYTE)
  124.     mov    bl, ah            ; copy the entry number (clear high BYTE)
  125.     mov    ax, bx            ; bx <- entry * 3
  126.     sal    ax, 1
  127.     add    bx, ax
  128.     add    bx, [frameptr]        ; bx <- frameptr + (entry * 3)
  129.     mov    al, [s_stack+bx.data.page]
  130.     mov    [regs+di.bpage], al
  131.     mov    ax, [s_stack+bx.data.disp]
  132.     mov    [regs+di.disp], ax
  133.     jmp    next
  134. ENDP    ld_local
  135.  
  136. ;************************************************************************
  137. ;*                            al    ah    *
  138. ;* Store into local stack frame            STLOCAL src,    entry    *
  139. ;************************************************************************
  140. PROC    st_local
  141.     get2op
  142.     mov    bl, al            ; copy destination register number
  143.     mov    di, bx            ;    into di (clear high order BYTE)
  144.     mov    bl, ah            ; copy the entry number (clear high BYTE)
  145.     mov    ax, bx            ; bx <- entry * 3
  146.     sal    ax, 1
  147.     add    bx, ax
  148.     add    bx, [frameptr]        ; bx <- frameptr + (entry * 3)
  149.     mov    al, [regs+di.bpage]
  150.     mov    dx, [regs+di.disp]
  151.     mov    [s_stack+bx.data.page], al
  152.     mov    [s_stack+bx.data.disp], dx
  153.     jmp    next
  154. ENDP    st_local
  155.  
  156. ;************************************************************************
  157. ;*                        al    al    ah    *
  158. ;* Load from higher lexical level    LDLEX    dest,    entry,    lvl    *
  159. ;************************************************************************
  160. PROC    ld_lex
  161.     get1op
  162.     push    ax
  163.     get2op
  164.     save    <si>            ; save current location pointer
  165.     mov    bl, ah            ; clear high order BYTE of the lexical
  166.     mov    cx, bx            ;    level number delta and move to cx
  167.     mov    bl, al            ; align, and save entry number
  168.     push    bx
  169.     call    delta_lv        ; get pointer to parent's stack frame
  170.     pop    ax            ; get entry number
  171.     mov    bx, ax            ; bx <- entry number * 3
  172.     shl    ax, 1
  173.     add    bx, ax
  174.     pop    di            ; get destination register number
  175.     mov    al, [(STKFDEF es:si+bx).data.page]
  176.     mov    bx, [(STKFDEF es:si+bx).data.disp]
  177.     mov    [regs+di.bpage], al
  178.     mov    [regs+di.disp], bx
  179.     jmp    next_pc
  180. ENDP    ld_lex
  181.  
  182. ;************************************************************************
  183. ;*                        al    al    ah    *
  184. ;* Store into higher lexical level    STLEX    src,    entry,    lvl    *
  185. ;************************************************************************
  186. PROC    st_lex
  187.     get1op
  188.     push    ax
  189.     get2op
  190.     save    <si>
  191.     mov    bl, ah
  192.     mov    cx, bx
  193.     mov    bl, al            ; align, and save entry number
  194.     push    bx
  195.     call    delta_lv        ; get pointer to parent's stack frame
  196.     pop    ax            ; get entry number
  197.     mov    bx, ax            ; bx <- entry number * 3
  198.     shl    ax, 1
  199.     add    bx, ax
  200.     pop    di            ; get source register number
  201.     mov    al, [regs+di.bpage]
  202.     mov    dx, [regs+di.disp]
  203.     mov    [(STKFDEF es:si+bx).data.page], al
  204.     mov    [(STKFDEF es:si+bx).data.disp], dx
  205.     jmp    next_pc
  206. ENDP    st_lex
  207.  
  208. ;************************************************************************
  209. ;*                        ax    al    ah    *
  210. ;* Call local routine            CALL    lbl,delta-lvl,delta-heap*
  211. ;************************************************************************
  212. PROC    call_lcl
  213.     lea    ax, [cs:next_pc]    ; For a "CALL", make a tail
  214.     push    ax            ; recursive call to following routine
  215. ;    jmp    call_local        ; fall thru
  216. ENDP    call_lcl
  217. PROC    call_local
  218.     lods    [WORD es:si]
  219.     mov    dx, ax
  220.  
  221.     lods    [WORD es:si]
  222.     inc    al            ; increment releative lexical level
  223.     mov    bl, al            ; isolate delta-lvl and save it
  224.     push    bx
  225.     mov    bl, ah            ; isolate delta-heap and save it, too
  226.     push    bx
  227.  
  228.     add    dx, si            ; compute branch destination address
  229.     mov    [save_si], dx        ; store updated location counter
  230.  
  231.     call    new_sf            ; allocate new stack frame on top of stack
  232.     mov    si, bx            ; save pointer to new stack frame
  233.  
  234.     pop    cx            ; restore the delta-heap argument
  235.     call    delta_hp        ; determine new heap env pointer
  236.     mov    [s_stack+si.heap.page], bl
  237.     mov    [s_stack+si.heap.disp], di
  238.  
  239.     pop    cx            ; restore the delta-lvl argument
  240.     push    si            ; save new stack frame pointer
  241.     call    delta_lv        ; get static link
  242.     pop    si            ; retrieve new stack frame pointer
  243.     mov    [s_stack+si.statlink.disp], bx
  244.  
  245.     mov    [frameptr], si
  246.     ret
  247. ENDP    call_local
  248.  
  249. ;************************************************************************
  250. ;*                        ax    al    ah    *
  251. ;* Call local routine tail recursively    CALL-TR lbl,delta-lvl,delta-heap*
  252. ;************************************************************************
  253. PROC    call_ltr
  254.     lea    ax, [cs:next_pc]    ; For a "CALL-TR", make a tail
  255.     push    ax            ; recursive call to following routine
  256. ;    jmp    call_local_tr        ; fall thru
  257. ENDP    call_ltr
  258. PROC    call_local_tr
  259.     lods    [WORD es:si]
  260.     mov    dx, ax
  261.  
  262.     lods    [WORD es:si]
  263.     inc    al            ; increment releative lexical level
  264.     mov    bl, al            ; isolate delta-lvl and save it
  265.     push    bx
  266.     mov    bl, ah            ; isolate delta-heap and save it, too
  267.     mov    cx, bx
  268.  
  269.     add    dx, si            ; compute branch destination address
  270.     mov    [save_si], dx        ; store updated location counter
  271.  
  272.     mov    ax, [frameptr]
  273.     mov    si, ax
  274.     add    ax, SIZE STKFDEF-SIZE POINTER
  275.     mov    [topofstack], ax    ; drop any local var's off top of stack
  276.  
  277.     call    delta_hp        ; determine new heap env pointer
  278.     mov    [s_stack+si.heap.page], bl
  279.     mov    [s_stack+si.heap.disp], di
  280.  
  281.     mov    [s_stack+si.closure.page], NIL_PAGE*2
  282.     mov    [s_stack+si.closure.disp], NIL_DISP
  283.  
  284.     pop    cx            ; restore the delta-lvl argument
  285.     push    si            ; save pointer to stack frame
  286.     call    delta_lv        ; get static link
  287.     pop    si
  288.     mov    [s_stack+si.statlink.disp], bx
  289.     ret
  290. ENDP    call_local_tr
  291.  
  292. ;************************************************************************
  293. ;*                            al    ah    *
  294. ;* Call closed procedure        CALL-CLOSURE    ftn,    #args    *
  295. ;*                                    *
  296. ;* Purpose:    Scheme interpreter support for procedure calls to fully    *
  297. ;*    closed functions                        *
  298. ;************************************************************************
  299. PROC    call_clo
  300.     lea    ax, [cs:next_pc]    ; For a "CALL-CLOSURE" make a tail
  301.     push    ax            ; recursive call to the following routine
  302.     get2op
  303. ;    jmp    call_closure        ; fall thru
  304. ENDP    call_clo
  305. PROC    call_closure
  306.     mov    bl, ah            ; isolate the number of arguments passed
  307.     push    bx
  308.     mov    bl, al            ; copy the procedure object register
  309.     mov    di, [regs+bx.page]    ; load page number of closure pointer
  310.     cmp    [ptype+di], CLOSTYPE
  311.     je    @@regular
  312.     jmp    call_continuation
  313. @@regular:
  314.     push    bx            ; save number of procedure pointer reg
  315.     call    new_sf            ; allocate a new stack frame
  316.     pop    si
  317. call_non_tr:                ; Load the pointer to the closure object from the operand register
  318.     push    si            ; save number of register containing closure
  319.     mov    di, [regs+si.page]
  320.     mov    si, [regs+si.disp]
  321.     ldpage    es, di
  322.  
  323.     mov    ax, di            ; Put the closure pointer into the newly allocated stack frame
  324.     mov    [s_stack+bx.closure.page], al
  325.     mov    [s_stack+bx.closure.disp], si
  326.  
  327.     mov    al, [(CLOSDEF es:si).heap.page]
  328.     mov    dx, [(CLOSDEF es:si).heap.disp]
  329.     mov    [s_stack+bx.heap.page], al
  330.     mov    [s_stack+bx.heap.disp], dx
  331.     mov    [s_stack+bx.statlink.disp], 0
  332.  
  333.     mov    [frameptr], bx        ; Obtain the entry point address from the closure object
  334.     mov    ax, [(CLOSDEF es:si).codeblk.disp]
  335.     mov    [cb_reg.disp], ax
  336.     add    ax, [(CLOSDEF es:si).entry.val]
  337.     mov    [save_si], ax        ; and set up for load into location pointer
  338.     xor    ax, ax
  339.     mov    al, [(CLOSDEF es:si).codeblk.page]
  340.     mov    [cb_reg.bpage], al
  341.                     ; Determine if the closed function is a mulambda
  342.     pop    di cx            ; get closure, # args passed
  343.     mov    ax, [(CLOSDEF es:si).args.val]
  344.     or    ax, ax
  345.     jl    @@mulambda
  346.     cmp    ax, cx            ; verify args passed/expected agree
  347.     je    @@ret
  348. @@wrongargs:
  349.     lea    di, [regs+di]
  350.     push    es            ; save es over C call
  351.     call    wrong_args C, cx, di    ; print error message and fixup VM regs
  352.     pop    es
  353.     restore <si>
  354.     pop    ax            ; drop the (fake) return address
  355.     jmp    sch_err
  356. @@ret:
  357.     ret
  358. @@mulambda:
  359.     push    di            ; we nee regs purty bad. save the source pointer
  360.     mov    si, cx            ; compute the address of the last
  361.     shl    si, 1            ; register which contains an argument
  362.     shl    si, 1            ; to be passed to the mulambda
  363.     lea    si, [regs+si]
  364.  
  365.     cmp    cx, NUM_REGS - 2    ; is tail in R62 ?
  366.     jae    @@manyargs
  367.     lea    di, [si+SIZE REG]    ; di is first free reg
  368.     mov    [(REG di).disp], NIL_DISP ; if not, nil-terminate the arglist
  369.     mov    [(REG di).page], NIL_PAGE
  370.     jmp    @@taildone
  371. @@manyargs:
  372.     mov    di, si            ; in this case, just take the last one
  373.     sub    si, SIZE REGS        ; as tail
  374.     dec    ax            ; one less cons to perform
  375. @@taildone:
  376.     mov    dx, cx            ; save number of arguments passed
  377.     add    cx, ax            ; adjust number of arguments passed
  378.     inc    cx            ; by number required
  379.     jg    @@loop
  380.     je    @@muret
  381.  
  382.     mov    cx, dx            ; restore count of args passed
  383.     pop    di            ; restore the source reg for error handling
  384.     jmp    @@wrongargs
  385.  
  386. @@loop:
  387.     push    es cx            ; save cx,es over C call
  388.     call    cons C, si, si, di    ; cons together ptrs in regs "n" and "n+1"
  389.     pop    cx es
  390.     mov    [(REG di).page], UN_PAGE*2
  391.     mov    [(REG di).disp], UN_DISP
  392.     mov    di, si            ; update pointers for next iteration
  393.     sub    si, SIZE REG
  394.     loop    @@loop            ; repeat for all arguments passed
  395. @@muret:
  396.     pop    di            ; trash the source reg
  397.     ret
  398.  
  399. call_continuation:            ; Function call is invoking a continuation-- unless we've got an error
  400.     cmp    [ptype+di], CONTTYPE
  401.     je    @@contok
  402.     add    bx, OFFSET regs
  403.     pop    ax            ; drop the # of arguments
  404.     push    es            ; save es over C call
  405.     call    not_procedural C, bx, ax
  406.     pop    es
  407.     restore <si>
  408.     pop    ax            ; drop the (fake) return address
  409.     jmp    sch_err
  410.  
  411. ;    Oh, wow! we've got a continuation to invoke
  412. ;
  413. ;    Note:    the contents of the stack is restored by making the VM's
  414. ;    previous stack segment register point to the continuation
  415. ;    object and signaling an underflow condition.    This restores
  416. ;    the stack, base, topofstack, PREV_page, and PREV_disp.    The
  417. ;    remainder of this code fetches the values of CB_page,
  418. ;    CB_disp, frameptr, and LP from the continuation object.
  419. @@contok:
  420.     push    bx            ; save pointer to continuation object
  421.     mov    al, [regs+bx.bpage]    ; copy continuation pointer into prev_reg
  422.     mov    dx, [regs+bx.disp]
  423.     mov    [prev_reg.bpage], al
  424.     mov    [prev_reg.disp], dx
  425.  
  426.     call    stk_unfl C
  427.  
  428.     pop    di            ; retrieve ptr to reg with continuation ptr.
  429.     mov    bx, [regs+di.page]    ; make es:[si] point to the continuation
  430.     ldpage    es, bx
  431.     mov    si, [regs+di.disp]
  432.  
  433.     xor    bx, bx
  434.     mov    bl, [(CONTDEF es:si).codeblk.page]
  435.     mov    ax, [(CONTDEF es:si).codeblk.disp]
  436.     mov    [cb_reg.bpage], bl
  437.     mov    [cb_reg.disp], ax
  438.  
  439.     add    ax, [(CONTDEF es:si).retaddr.val] ; restore return address displacement
  440.     mov    [save_si], ax
  441.  
  442.     mov    ax, [(CONTDEF es:si).dynlink.val] ; restore frameptr from dynamic link
  443.     sub    ax, [base]        ; adjust for current stack buffer base
  444.     mov    [frameptr], ax
  445.  
  446.     mov    al, [(CONTDEF es:si).fluid.page] ; restore fluid environment (FNV_reg)
  447.     mov    dx, [(CONTDEF es:si).fluid.disp]
  448.     mov    [fnv_reg.bpage], al
  449.     mov    [fnv_reg.disp], dx
  450.  
  451.     mov    al, [(CONTDEF es:si).globenv.page] ; restore global environment (GNV_reg)
  452.     mov    dx, [(CONTDEF es:si).globenv.disp]
  453.     mov    [gnv_reg.bpage], al
  454.     mov    [gnv_reg.disp], dx
  455.  
  456.     pop    ax            ; get number of arguments passed
  457.     cmp    ax, 1            ; one argument passed?
  458.     jne    @@conterror
  459.     ret
  460. @@conterror:
  461.     add    di, OFFSET regs        ; load address of continuation's register
  462.     push    es            ; save es over C call
  463.     call    wrong_args C, ax, di    ; print error message and fixup VM regs
  464.     pop    es
  465.     restore <si>
  466.     pop    ax            ; drop (fake) return address
  467.     jmp    sch_err
  468. ENDP    call_closure
  469.  
  470. ;************************************************************************
  471. ;*                            al    ah    *
  472. ;* Call closed proc tail recursively    CALL-CLOSURE-TR ftn,    #args    *
  473. ;*                                    *
  474. ;* Purpose:    Scheme interpreter support for procedure calls to fully    *
  475. ;*    closed functions tail recursively                *
  476. ;************************************************************************
  477. PROC    call_ctr
  478.     lea    ax, [cs:next_pc]    ; For "CALL-CLOSURE-TR" make tail
  479.     push    ax            ;    recursive call to the following routine
  480.     get2op
  481. ;    jmp    call_closed_tr        ; fall thru
  482. ENDP    call_ctr
  483. PROC    call_closed_tr
  484.     mov    bl, ah            ; isolate the number of arguments
  485.     push    bx
  486.     mov    bl, al            ; copy the procedure object register
  487.     mov    di, [regs+bx.page]    ; load page number of procedure object
  488.     cmp    [ptype+di], CLOSTYPE
  489.     je    @@regular
  490.     jmp    call_continuation
  491.  
  492. @@regular:
  493.     mov    si, bx            ; copy reg number with closure pointer
  494.     mov    ax, [frameptr]        ; use current stack frame for this call
  495.     mov    bx, ax            ; drop any local vars from top of stack
  496.     add    ax, SIZE STKFDEF-SIZE POINTER
  497.     mov    [topofstack], ax
  498.  
  499.     jmp    call_non_tr
  500. ENDP    call_closed_tr
  501.  
  502. ;************************************************************************
  503. ;* Call/cc local            CALL/CC    lbl,delta-lvl,delta-heap*
  504. ;*                                    *
  505. ;* Purpose:    Interpreter support for a local call with current    *
  506. ;*    continuation                            *
  507. ;*                                    *
  508. ;* Description:                                *
  509. ;*    1.    The local CALL support is called to create a new    *
  510. ;*    stack frame and to establish the VM's registers            *
  511. ;*    for the branch to the called routine.                *
  512. ;*    2.    A stack overflow condition is signaled to cause        *
  513. ;*    the contents of the stack to be saved on the heap        *
  514. ;*    in a continuation object format.                *
  515. ;*    3.    Fields in the continuation object are updated to    *
  516. ;*    cause control to return to the correct place when        *
  517. ;*    the continuation is invoked.                    *
  518. ;*    4.    Control returns to the Scheme interpreter.        *
  519. ;************************************************************************
  520. PROC    call_cc
  521.     call    call_local        ; call CALL's alternate entry point
  522. in_call_cc:
  523.     call    stk_ovfl C        ; signal stack overflow
  524.  
  525.     mov    bx, [prev_reg.page]    ; move pointer to continuation into R1
  526.     mov    di, [prev_reg.disp]
  527.     mov    [reg1.page], bx
  528.     mov    [reg1.disp], di
  529.     ldpage    es, bx
  530.  
  531.     mov    si, [frameptr]        ; create a pointer to the current stack
  532.     add    si, OFFSET s_stack    ; frame (the new one)
  533.  
  534.     mov    al, [(STKFDEF si).codeblk.page] ; copy the value of the VM's code base
  535.     mov    dx, [(STKFDEF si).codeblk.disp]
  536.     mov    [(CONTDEF es:di).codeblk.page], al ; into the continuation object
  537.     mov    [(CONTDEF es:di).codeblk.disp], dx
  538.  
  539.     mov    ax, [(STKFDEF si).retaddr.disp]
  540.     mov    [(CONTDEF es:di).retaddr.val], ax
  541.  
  542.     mov    ax, [(STKFDEF si).dynlink.disp]
  543.     mov    [(CONTDEF es:di).dynlink.val], ax
  544.  
  545.     jmp    next_pc
  546. ENDP    call_cc
  547.  
  548. ;************************************************************************
  549. ;* Call/cc tail recursively    CALL/CC-TR    lbl,delta-lvl,delta-heap*
  550. ;*                                    *
  551. ;* Purpose:    Interpreter support for a tail recursive local call with*
  552. ;*    current continuation                        *
  553. ;*                                    *
  554. ;* Description:                                *
  555. ;*    1.    The local CALL-TR support is called to update the    *
  556. ;*    current stack frame and to establish the VM's            *
  557. ;*    registers for the branch to the called routine.            *
  558. ;*    2.    Control transfers to the CALL/CC support to create    *
  559. ;*    the continuation object.                    *
  560. ;************************************************************************
  561. PROC    cl_cctr
  562.     call    call_local_tr
  563.     jmp    in_call_cc
  564. ENDP    cl_cctr
  565.  
  566. ;************************************************************************
  567. ;*                                al    *
  568. ;* Call/cc with of procedure object        CALL/CC-CLOSURE    ftn    *
  569. ;*                                    *
  570. ;* Purpose:    Interpreter support for a call with current continuation*
  571. ;*    of a fully closed function                    *
  572. ;************************************************************************
  573. PROC    clcc_c
  574.     get1op
  575.     mov    ah, 1            ; indicate one argument being passed
  576.     push    ax            ;    and save "operands"
  577.  
  578.     mov    ax, [frameptr]        ; save current stack frame pointer
  579.     add    ax, [base]
  580.     push    ax
  581.  
  582.     mov    ax, [topofstack]    ; update frameptr to where it will be
  583.     add    ax, SIZE POINTER    ; after the new stack frame is built
  584.     mov    [frameptr], ax
  585.  
  586.     call    stk_ovfl C        ; signal stack overflow to create
  587.                     ;    continuation data object
  588.  
  589.     mov    bx, [prev_reg.page]    ; load pointer to continuation
  590.     mov    di, [prev_reg.disp]
  591.     ldpage    es, bx
  592.  
  593.     mov    al, [cb_reg.bpage]
  594.     mov    dx, [cb_reg.disp]
  595.     mov    [(CONTDEF es:di).codeblk.page], al
  596.     mov    [(CONTDEF es:di).codeblk.disp], dx
  597.  
  598.     sub    si, dx
  599.     mov    [(CONTDEF es:di).retaddr.val], si
  600.     add    si, dx
  601.  
  602.     pop    ax            ; define dynamic link in continuation
  603.     mov    [(CONTDEF es:di).dynlink.val], ax
  604.     sub    ax, [base]        ; put frameptr back to where it should be
  605.     mov    [frameptr], ax        ; Note:    frameptr's now negative (topofstack is 0)
  606.  
  607.     mov    al, [prev_reg.bpage]    ; Perform the Call-Closure-Tail-Recursive
  608.     mov    dx, [prev_reg.disp]
  609.     mov    [tm2_reg.bpage], al
  610.     mov    [tm2_reg.disp], dx
  611.     pop    ax            ; recover "operands" to call-closure
  612.     call    call_closure
  613.     mov    al, [tm2_reg.bpage]
  614.     mov    dx, [tm2_reg.disp]
  615.     mov    [reg1.bpage], al
  616.     mov    [reg1.disp], dx
  617.     jmp    next_pc
  618. ENDP    clcc_c
  619.  
  620. ;************************************************************************
  621. ;*                                al    *
  622. ;* Call/cc with of procedure object    CALL/CC-CLOSURE-TR    ftn    *
  623. ;*                                    *
  624. ;* Purpose: Interpreter support for a tail recursive call with current    *
  625. ;*    continuation of a fully closed function                *
  626. ;*                                    *
  627. ;* Description:                                *
  628. ;*    1.    The CALL/CC-CLOSURE argument is fetched.        *
  629. ;*    2.    The current continuation is formed using the        *
  630. ;*    caller's return address (since there's no way to        *
  631. ;*    return here from the tail recursive call).            *
  632. ;*    The pointer to the continuation is placed into            *
  633. ;*    VM register 1.                            *
  634. ;*    3.    The CALL-CLOSURE-TR code is called to complete the    *
  635. ;*    call sequence.                            *
  636. ;************************************************************************
  637. PROC    clcc_ctr
  638.     get1op
  639.     mov    ah, 1            ; indicate one argument being passed
  640.     push    ax            ;    and save "operands"
  641.  
  642.     call    stk_ovfl C        ; signal stack overflow to create
  643.                     ;    continuation data object
  644.  
  645.     mov    bx, [prev_reg.page]    ; load pointer to continuation
  646.     mov    di, [prev_reg.disp]
  647.     ldpage    es, bx
  648.  
  649.     mov    si, [frameptr]        ; create a pointer to the current stack
  650.     add    si, OFFSET s_stack    ; frame (the new one)
  651.  
  652.     mov    al, [(STKFDEF si).codeblk.page]
  653.     mov    dx, [(STKFDEF si).codeblk.disp]
  654.     mov    [(CONTDEF es:di).codeblk.page], al
  655.     mov    [(CONTDEF es:di).codeblk.disp], dx
  656.  
  657.     mov    ax, [(STKFDEF si).retaddr.disp]
  658.     mov    [(CONTDEF es:di).retaddr.val], ax
  659.  
  660.     mov    ax, [(STKFDEF si).dynlink.disp]
  661.     mov    [(CONTDEF es:di).dynlink.val], ax
  662.  
  663.     mov    al, [prev_reg.bpage]    ; Perform the Call-Closure-Tail-Recursive
  664.     mov    dx, [prev_reg.disp]
  665.     mov    [tm2_reg.bpage], al
  666.     mov    [tm2_reg.disp], dx
  667.     pop    ax            ; recover "operands" to call-closure-tr
  668.     call    call_closed_tr
  669.     mov    al, [tm2_reg.bpage]
  670.     mov    dx, [tm2_reg.disp]
  671.     mov    [reg1.bpage], al
  672.     mov    [reg1.disp], dx
  673.     jmp    next_pc
  674. ENDP    clcc_ctr
  675.  
  676. ;************************************************************************
  677. ;*                            al    ah    *
  678. ;* Apply closure            APPLY-CLOSURE    ftn,    args    *
  679. ;*                                    *
  680. ;* Purpose:    Interpreter support for the "apply" primitive.    The    *
  681. ;*    argument list (in register "args") are to be passed        *
  682. ;*    to the closure pointed to by the "ftn" register.        *
  683. ;*                                    *
  684. ;* Note:    The argument registers may be anything that the compiler*
  685. ;*    decides on, so the "ftn" pointer could be destroyed        *
  686. ;*    in the process of loading the arguments of the argument     *
  687. ;*    list ("args") into the VM general registers R1-Rn.        *
  688. ;*    So that the ftn pointer is not lost during this process,    *
  689. ;*    this pointer is pushed onto the 8088 stack before the        *
  690. ;*    call to process the arguments, and it is restored into        *
  691. ;*    the last available register to complete the call        *
  692. ;*    sequence.                            *
  693. ;*                                    *
  694. ;*    Garbage collection will not occur during the argument loading    *
  695. ;*    process (arguments are copied, but no cons-ing occurs),        *
  696. ;*    so it's safe to save the "ftn" pointer on the 8088        *
  697. ;*    stack temporarily.                        *
  698. ;************************************************************************
  699. last_reg    EQU    (regs + (NUM_REGS - 1) * SIZE REG)
  700. PROC    apply
  701.     get2op
  702.     mov    bl, al            ; copy closure pointer register number
  703.     push    [regs+bx.page]        ; save value of register containing
  704.     push    [regs+bx.disp]        ;    the closure pointer
  705.     save    <si>
  706.     call    aply_arg        ; expand arguments into R1-Rn
  707.     restore <si>
  708.     pop    [last_reg.disp]
  709.     pop    [last_reg.page]
  710.     mov    ah, cl            ; copy the argument count to ah, al<="Rlast"
  711.     mov    al, last_reg - regs
  712.     call    call_closure
  713.     jmp    next_pc
  714. ENDP    apply
  715.  
  716. ;************************************************************************
  717. ;*                            al    ah    *
  718. ;* Apply closure, tail recursively    APPLY-CLOSURE-TR ftn,    args    *
  719. ;*                                    *
  720. ;* Purpose:    Interpreter support for the "apply" primitive.    The    *
  721. ;*    argument list (in register "args") are to be passed        *
  722. ;*    to the closure pointed to by the "ftn" register.        *
  723. ;*                                    *
  724. ;* Note:    See notes in "APPLY-CLOSURE" support, above.        *
  725. ;************************************************************************
  726. PROC    apply_tr
  727.     get2op
  728.     mov    bl, al            ; copy closure pointer register number
  729.     push    [regs+bx.page]        ; save value of register containing
  730.     push    [regs+bx.disp]        ;    the closure pointer
  731.     save    <si>
  732.     call    aply_arg        ; expand arguments into R1-Rn
  733.     restore <si>
  734.     pop    [last_reg.disp]
  735.     pop    [last_reg.page]
  736.     mov    ah, cl            ; copy the argument count to ah, al<="Rlast"
  737.     mov    al, last_reg - regs
  738.     call    call_closed_tr
  739.     jmp    next_pc
  740. ENDP    apply_tr
  741.  
  742. ;************************************************************************
  743. ;* Execute code block    EXECUTE    CODE                    *
  744. ;*                                    *
  745. ;* Purpose: Interpreter support for the "execute" primitive operation.    *
  746. ;*                                    *
  747. ;* Description:    The execute primitive causes a code block to be        *
  748. ;*    executed in a new environment.    This is accomplished        *
  749. ;*    by executing a procedure call to the code block with        *
  750. ;*    no static environment information available.    The        *
  751. ;*    new stack frame has a nil heap environment pointer, and     *
  752. ;*    the static link is set to point to itself to prevent        *
  753. ;*    access to any higher lexical levels.    When the code        *
  754. ;*    block exits, control will return to the place where the     *
  755. ;*    execute instruction was executed.                *
  756. ;************************************************************************
  757. PROC    execute
  758.     get1op
  759.     mov    bx, ax
  760. @@retry:
  761.     mov    di, [regs+bx.page]
  762.     cmp    [ptype+di], CODETYPE
  763.     je    @@simplecode
  764.     cmp    [ptype+di], I86TYPE
  765.     je    @@simpleinline
  766.     jmp    @@load
  767. @@simpleinline:
  768.     save    <si>
  769.     mov    si, [regs+bx.disp]    ; get entry point
  770.     add    si, OFFSET (TYPE I86DEF).data
  771.     ldpage    bx, di
  772.     push    bp
  773.     push    cs
  774.     lea    ax, [cs:@@inlineret]
  775.     push    ax
  776.     push    bx si
  777.     lea    si, [regs]        ; pass on some information
  778.     lea    di, [@@disptable]
  779.     retf                ; call code
  780. @@inlineret:
  781.     pop    bp
  782.     jmp    next_pc
  783. DATASEG
  784. LABEL    @@disptable    DWORD
  785.     DD    $$loadpage        ; provide access to most useful routines
  786.     DD    alloc_big_block
  787.     DD    alloc_block
  788.     DD    alloc_flonum
  789.     DD    alloc_int
  790.     DD    alloc_list_cell
  791.     DD    alloc_string
  792.     DD    cons
  793.     DD    free
  794.     DD    GETCH
  795.     DD    get_max_cols
  796.     DD    get_max_rows
  797.     DD    int2long
  798.     DD    is_graph_mode
  799.     DD    long2int
  800.     DD    malloc
  801.     DD    nosound
  802.     DD    sound
  803.     DD    zcuroff
  804.     DD    zcuron
  805.     DD    zprintf
  806.     DD    zputc
  807.     DD    zscroll
  808.     DD    zscroll_d
  809. CODESEG
  810. PROC C    $$loadpage FAR @@page:WORD        ; provide a far linkage to the code
  811.     ldpage    ax, [regs+62*(SIZE REGS).page]    ; refresh the current block
  812.     ldpage    ax, [@@page]
  813.     ret
  814. ENDP    $$loadpage
  815.  
  816. @@simplecode:
  817.     push    bx
  818.     call    new_sf            ; create a new stack frame for the "call"
  819.     mov    [s_stack+bx.statlink.disp], 0
  820.     mov    al, [gnv_reg.bpage]    ; default environment to global env
  821.     mov    dx, [gnv_reg.disp]
  822.     mov    [s_stack+bx.heap.page], al
  823.     mov    [s_stack+bx.heap.disp], dx
  824.     mov    [frameptr], bx
  825.     pop    bx            ; retrieve the code pointer's reg number
  826.     mov    si, [regs+bx.disp]    ; define the code base register
  827.     mov    bl, [regs+bx.bpage]
  828.     mov    [cb_reg.disp], si
  829.     mov    [cb_reg.bpage], bl
  830.     xor    bh, bh
  831.     ldpage    es, bx
  832.     add    si, [(CODEDEF es:si).entry.val] ; adjust location ptr for entry OFFSET
  833.     jmp    next
  834.  
  835. ;    Object to be executed is not a code block, so we've got to create
  836. ;    one for a compiled program before executing it.    The format of an
  837. ;    object program is:
  838. ;
  839. ;    (PCS-CODE-BLOCK #-constants #-codebytes (constant ...) (codebyte ...))
  840. ;    or:
  841. ;    (PCS-INLINE-BLOCK #-asmbytes (asmbyte ...))
  842. ;
  843. @@load:
  844.     save    <bx, si>        ; save dest register, location pointer
  845.     cmp    [ptype+di], LISTTYPE
  846.     jne    @@badheader
  847.     ldpage    es, di
  848.     mov    si, [regs+bx.disp]
  849.     mov    bl, [(LISTDEF es:si).car.page]
  850.     mov    si, [(LISTDEF es:si).car.disp]
  851.     cmp    [ptype+bx], SYMBTYPE
  852.     jne    @@badheader
  853.     ldpage    es, bx
  854.     mov    cl, [(SYMDEF es:si+4).buffer] ; get 5th char
  855.     ldpage    es, di
  856.     restore    <bx>
  857.     mov    si, [regs+bx.disp]
  858.     mov    bl, [(LISTDEF es:si).cdr.page]
  859.     mov    si, [(LISTDEF es:si).cdr.disp]
  860.     cmp    [ptype+bx], LISTTYPE
  861.     jne    @@badheader
  862.     ldpage    es, bx
  863.     cmp    [(LISTDEF es:si).car.page], SPECFIX*2
  864.     je    @@firstfixok
  865. @@badheader:
  866.     lea    ax, [@@msg]
  867. DATASEG
  868. @@msg    DB    "%EXECUTE", 0
  869. CODESEG
  870.     restore <bx>            ; load number of register containing
  871.     add    bx, OFFSET regs        ; the "code" pointer and compute its addr
  872.     mov    cx, 1            ; load argument count = 1
  873.     push    es            ; save es over C call
  874.     call    set_src_error C, ax, cx, bx
  875.     pop    es
  876.     restore <si>
  877.     jmp    sch_err
  878.  
  879. @@firstfixok:
  880.     mov    ax, [(LISTDEF es:si).car.disp]
  881.     cmp    cl, 'I'            ; was it 'PCS-C... or 'PCS-I ?
  882.     jne    @@codeblock
  883.     jmp    @@inline
  884. @@codeblock:
  885.     inc    ax            ; add a constant for entry point address
  886.     mov    dx, ax            ; dx <- ax * 3
  887.     shl    ax, 1
  888.     add    dx, ax
  889.     mov    bl, [(LISTDEF es:si).cdr.page]
  890.     mov    si, [(LISTDEF es:si).cdr.disp]
  891.     cmp    [ptype+bx], LISTTYPE
  892.     jne    @@badheader
  893.     ldpage    es, bx
  894.     cmp    [(LISTDEF es:si).car.page], SPECFIX*2
  895.     jne    @@badheader
  896.     mov    ax, [(LISTDEF es:si).car.disp]
  897.     add    ax, dx            ; add constants*3 + codebytes
  898.     mov    bx, CODETYPE
  899.     push    dx            ; save the entry point
  900.     call    alloc_block C, [tmp_adr], bx, ax
  901.     mov    di, [tmp_reg.page]
  902.     ldpage    es, di
  903.     mov    dx, di            ; save code block's page number in dx
  904.     mov    di, [tmp_reg.disp]
  905.     add    di, SIZE POINTER    ; advance di past block header
  906.     mov    al, SPECFIX*2        ; store tag=fixnum for entry point address
  907.     stosb
  908.     pop    ax            ; store entry point address
  909.     add    ax, SIZE POINTER    ; adjust entry point for block header
  910.     stosw
  911.  
  912. ;    reload pointer to object program [Note:    garbage collection may have
  913. ;    copied the linked list representation of the program, so pointers
  914. ;    held in TIPC registers may not be valid.]
  915.  
  916.     restore <bx>
  917.     mov    si, [regs+bx.page]    ; load pointer to "object program"
  918.     ldpage    es, si
  919.     mov    si, [regs+bx.disp]
  920.     mov    bl, [(LISTDEF es:si).cdr.page]
  921.     mov    si, [(LISTDEF es:si).cdr.disp]
  922.     ldpage    es, bx
  923.     mov    cx, [(LISTDEF es:si).car.disp]
  924.     mov    bl, [(LISTDEF es:si).cdr.page]
  925.     mov    si, [(LISTDEF es:si).cdr.disp]
  926.     ldpage    es, bx
  927.     mov    ax, [(LISTDEF es:si).car.disp]
  928.     mov    bl, [(LISTDEF es:si).cdr.page]
  929.     mov    si, [(LISTDEF es:si).cdr.disp]
  930.     cmp    [ptype+bx], LISTTYPE
  931.     jne    @@tobadheader
  932.     ldpage    es, bx            ; warning: ds is not the data segment
  933.     push    ax bx si ds        ; save # codebytes ptr to const's list cell
  934.     mov    bl, [(LISTDEF es:si).car.page]    ; load constant list header
  935.     mov    si, [(LISTDEF es:si).car.disp]
  936.     ldpage    es, dx
  937.     jcxz    @@constantsdone
  938. @@constantsloop:
  939.     cmp    bl, 0            ; end of constants list?
  940.     jne    @@moreconstants
  941. @@badconstants:
  942.     pop    ds
  943.     add    sp, 6            ; trash off
  944. @@tobadheader:
  945.     jmp    @@badheader
  946.  
  947. @@moreconstants:
  948.     cmp    [ss:ptype+bx], LISTTYPE
  949.     jne    @@badconstants
  950.     ldpage    ds, bx
  951.     movsb                ; copy car field to code block constants
  952.     movsw
  953.     mov    bl, [(POINTER si).page]; load the cdr
  954.     mov    si, [(POINTER si).disp]
  955.     loop    @@constantsloop
  956. @@constantsdone:
  957.     mov    ax, bx            ; save the current list page
  958.     pop    ds si bx cx        ; end of critical section
  959.     ldpage    es, bx
  960.     mov    bx, ax            ; restore the list page in [bl:si]
  961.  
  962.     cmp    bl, 0            ; end of list found?
  963.     jne    @@tobadheader
  964.     mov    bl, [(LISTDEF es:si).cdr.page] ; fetch pointer to code bytes
  965.     mov    si, [(LISTDEF es:si).cdr.disp]
  966.     cmp    [ptype+bx], LISTTYPE
  967.     jne    @@tobadheader
  968.     ldpage    es, bx
  969.     cmp    [(LISTDEF es:si).cdr.page], 0    ; last entry in object program list?
  970.     jne    @@tobadheader
  971.     mov    bl, [(LISTDEF es:si).car.page]    ; load header to bytecode list
  972.     mov    si, [(LISTDEF es:si).car.disp]
  973.     ldpage    es, dx
  974.     push    ds            ; warning: ds is not the data segment
  975. @@dataloop:
  976.     cmp    bl, 0            ; end of constants list?
  977.     je    @@badbytes
  978.     cmp    [ss:ptype+bx], LISTTYPE
  979.     jne    @@badbytes
  980.     ldpage    ds, bx
  981.     lodsb                ; load car's page number
  982.     cmp    al, SPECFIX*2
  983.     je    @@itsadatabyte
  984. @@badbytes:
  985.     pop    ds
  986.     jmp    @@badheader
  987. @@itsadatabyte:
  988.     lodsw                ; load immediate value
  989.     stosb                ; store low order BYTE into code block
  990.     mov    bl, [(POINTER si).page]; get the cdr
  991.     mov    si, [(POINTER si).disp]
  992.     loop    @@dataloop
  993.  
  994.     cmp    bl, 0            ; extraneous code bytes in list?
  995.     jne    @@badbytes
  996.     pop    ds            ; end of critical section
  997.     restore <bx, si>        ; re-fetch dest reg, location pointer
  998.     mov    ax, [tmp_reg.page]
  999.     mov    dx, [tmp_reg.disp]
  1000.     mov    [regs+bx.page], ax
  1001.     mov    [regs+bx.disp], dx
  1002.     jmp    @@retry
  1003.  
  1004. @@inline:
  1005.     push    ax
  1006.     mov    bx, I86TYPE
  1007.     call    alloc_block C, [tmp_adr], bx, ax
  1008.     mov    bx, [tmp_reg.page]
  1009.     mov    di, [tmp_reg.disp]
  1010.     ldpage    es, bx
  1011.     add    di, OFFSET (TYPE I86DEF).data
  1012.     pop    cx
  1013.     restore    <bx>
  1014.     mov    si, [regs+bx.disp]
  1015.     mov    bx, [regs+bx.page]
  1016.     push    ds            ; warning: ds is not the data segment
  1017.     ldpage    ds, bx
  1018.     mov    bl, [(LISTDEF si).cdr.page]
  1019.     mov    si, [(LISTDEF si).cdr.disp]
  1020.     ldpage    ds, bx
  1021.     mov    bl, [(LISTDEF si).cdr.page]
  1022.     mov    si, [(LISTDEF si).cdr.disp]
  1023.     cmp    [ss:ptype+bx], LISTTYPE
  1024.     jne    @@badinline
  1025.     mov    bl, [(LISTDEF si).car.page]
  1026.     mov    si, [(LISTDEF si).car.disp]
  1027. @@inlineloop:
  1028.     cmp    [ss:ptype+bx], LISTTYPE
  1029.     je    @@inlineok
  1030. @@badinline:
  1031.     pop    ds
  1032.     jmp    @@badheader
  1033. @@inlineok:
  1034.     ldpage    ds, bx
  1035.     cmp    [(LISTDEF si).car.page], SPECFIX*2
  1036.     jne    @@badinline
  1037.     mov    ax, [(LISTDEF si).car.disp]
  1038.     stosb
  1039.     mov    bl, [(LISTDEF si).cdr.page]
  1040.     mov    si, [(LISTDEF si).cdr.disp]
  1041.     loop    @@inlineloop
  1042.  
  1043.     cmp    bl, 0
  1044.     jne    @@badinline
  1045.     pop    ds            ; end of bad-ds section
  1046.     restore    <bx, si>
  1047.     mov    ax, [tmp_reg.page]
  1048.     mov    dx, [tmp_reg.disp]
  1049.     mov    [regs+bx.page], ax
  1050.     mov    [regs+bx.disp], dx
  1051.     jmp    @@retry
  1052. ENDP    execute
  1053.  
  1054. ;************************************************************************
  1055. ;* Exit from current procedure                    EXIT    *
  1056. ;*                                    *
  1057. ;* Description:    The internal registers of the VM are reset from        *
  1058. ;*    information stored in the current frame pointer to        *
  1059. ;*    restore the environment at the point where the current        *
  1060. ;*    procedure was called (i.e., control returns to the        *
  1061. ;*    calling routine).                        *
  1062. ;************************************************************************
  1063. PROC    s_exit
  1064.     mov    ax, [frameptr]
  1065.     mov    bx, ax
  1066.     add    bx, OFFSET s_stack    ; compute address of current stack frame
  1067.  
  1068.     sub    ax, SIZE POINTER    ; reset the current topofstack to previous
  1069.     mov    [topofstack], ax    ; value [frameptr - sizeof(pointer)]
  1070.  
  1071.     xor    ax, ax
  1072.     mov    al, [(STKFDEF bx).codeblk.page] ; load CB's page number
  1073.     mov    dx, [(STKFDEF bx).codeblk.disp]    ; update the current code base (CB)
  1074.     mov    [cb_reg.bpage], al
  1075.     mov    [cb_reg.disp], dx
  1076.  
  1077.     add    dx, [(STKFDEF bx).retaddr.disp]    ; load return address' location pointer
  1078.     mov    si, dx            ; and add in starting OFFSET of code block
  1079.  
  1080.     mov    ax, [(STKFDEF bx).dynlink.disp] ; compute pointer to caller's stack frame
  1081.     mov    bx, ax            ; get a copy of it
  1082.     sub    ax, [base]        ; frameptr <- dynamic link - base
  1083.     cmp    ax, STKSIZE        ; is new frameptr outside stack buffer?
  1084.     jb    @@inbounds
  1085.     push    bx es
  1086.     call    stk_unfl C        ; process stack underflow
  1087.     pop    es ax
  1088.     sub    ax, [base]        ; but this base is now OK
  1089. @@inbounds:
  1090.     mov    [frameptr], ax
  1091.     mov    bx, [cb_reg.page]
  1092.     ldpage    es, bx
  1093.     jmp    next
  1094. ENDP    s_exit
  1095.  
  1096. ;************************************************************************
  1097. ;*                        al    al    ah    *
  1098. ;* Create Closure        CR-CLOSE    dest,    label,    nargs    *
  1099. ;*                                    *
  1100. ;* Purpose:    Scheme interpreter support for the creation of closure    *
  1101. ;*    objects.                            *
  1102. ;************************************************************************
  1103. PROC    cr_close
  1104.     get1op
  1105.     mov    di, ax
  1106.     get2op
  1107.     mov    cx, ax
  1108.     get1op
  1109.     cbw
  1110.     add    cx, si            ; add in current location pointer
  1111.     sub    cx, [cb_reg.disp]    ; and adjust for code block OFFSET
  1112.     save    <si>
  1113.     push    ax cx di
  1114.     mov    dx, CLOSTYPE
  1115.     mov    ax, SIZE CLOSDEF-SIZE POINTER
  1116.     call    alloc_block C, [tmp_adr], dx, ax
  1117.  
  1118.     mov    bx, [tmp_reg.page]    ; load pointer to closure object
  1119.     mov    di, [tmp_reg.disp]
  1120.     ldpage    es, bx
  1121.  
  1122.     pop    si            ; copy contents of destination register
  1123.     mov    ax, di            ; Make the destination register point
  1124.     xchg    bl, [regs+si.bpage]    ; to the closure object
  1125.     xchg    ax, [regs+si.disp]
  1126.     mov    [(CLOSDEF es:di).info.page], bl
  1127.     mov    [(CLOSDEF es:di).info.disp], ax
  1128.  
  1129.     mov    al, SPECFIX*2
  1130.     mov    [(CLOSDEF es:di).entry.tag], al
  1131.     pop    [(CLOSDEF es:di).entry.val]
  1132.     mov    [(CLOSDEF es:di).args.tag], al
  1133.     pop    [(CLOSDEF es:di).args.val]
  1134.  
  1135.     mov    al, [cb_reg.bpage]    ; copy in pointer to current code base
  1136.     mov    dx, [cb_reg.disp]
  1137.     mov    [(CLOSDEF es:di).codeblk.page], al
  1138.     mov    [(CLOSDEF es:di).codeblk.disp], dx
  1139.  
  1140.     mov    si, [frameptr]
  1141.     mov    al, [s_stack+si.heap.page] ; define heap environment
  1142.     mov    dx, [s_stack+si.heap.disp]
  1143.     mov    [(CLOSDEF es:di).heap.page], al
  1144.     mov    [(CLOSDEF es:di).heap.disp], dx
  1145.  
  1146.     jmp    next_pc
  1147. ENDP    cr_close
  1148.  
  1149. ;************************************************************************
  1150. ;* Local support - stack overflow handler                *
  1151. ;*                                    *
  1152. ;* Purpose:    To move part of Scheme's runtime stack to the heap when    *
  1153. ;*    stack overflow occurs.                        *
  1154. ;*                                    *
  1155. ;* Description:    The contents of the stack which precede the current    *
  1156. ;*    stack frame are moved to the heap (in a continuation        *
  1157. ;*    object) and the current stack frame is moved to the        *
  1158. ;*    top of the stack buffer.                    *
  1159. ;*                                    *
  1160. ;* Input Parameters:                            *
  1161. ;*    TIPC register si - the value to be placed in the        *
  1162. ;*    "return address displacement" field of the            *
  1163. ;*    continuation (needed only for call/cc)                *
  1164. ;*    FNV_reg - the current fluid environment (saved by        *
  1165. ;*    call/cc)                            *
  1166. ;*    GNV_reg - the current global environment (saved by        *
  1167. ;*    call/cc)                            *
  1168. ;*    frameptr - the current stack frame pointer            *
  1169. ;*    base - the stack buffer base value                *
  1170. ;*    topofstack - the current top-of-stack pointer            *
  1171. ;*    CB - the VM register which points to the current        *
  1172. ;*    code block                            *
  1173. ;*    PREV_page,PREV_disp - the VM's previous stack segment        *
  1174. ;*    register                            *
  1175. ;*                                    *
  1176. ;* Output Parameters:                            *
  1177. ;*    PREV_page,PREV_disp - a pointer to the continuation        *
  1178. ;*    object which was created                    *
  1179. ;*    base - updated to the new base value (stack OFFSET)        *
  1180. ;*    due to movement of some of the stack contents            *
  1181. ;*    to the heap                            *
  1182. ;*                                    *
  1183. ;* Variables Modified:    (but logically unchanged)            *
  1184. ;*    frameptr - the current stack frame pointer            *
  1185. ;*    topofstack - the current top of stack pointer            *
  1186. ;*                                    *
  1187. ;* Example:    Stack Overflow Condition                *
  1188. ;*                                    *
  1189. ;*    Before                                *
  1190. ;*                                    *
  1191. ;*    +--------+----------------------+                *
  1192. ;*    |  prev stk seg -> = nil    |                *
  1193. ;*    +--------+----------------------+                *
  1194. ;*      Stack Buffer (base = 0)                    *
  1195. ;*    +--------+----------------------+                *
  1196. ;*    |    Contents        |                *
  1197. ;*    :    of            :                *
  1198. ;*    :    Stack            :                *
  1199. ;*    |    (m BYTEs)        |                *
  1200. ;*    |--------+----------------------|                *
  1201. ;*    |    Current            |<-frameptr            *
  1202. ;*    :    Stack            :                *
  1203. ;*    |    Frame            |<-topofstack            *
  1204. ;*    +--------+----------------------+                *
  1205. ;*                                    *
  1206. ;*    AFTER                                *
  1207. ;*                                    *
  1208. ;*    "Continuation" in Heap                        *
  1209. ;* +--------+-------------------+    +-------+------------------+    *
  1210. ;* |    prev stk seg ->        |------>| cont    | length (m+24)       |    *
  1211. ;* +--------+-------------------+    |-------+------------------|    *
  1212. ;*    Stack Buffer (base = m)        | segment's stack base = 0 |    *
  1213. ;* +--------+-------------------+    |--------+-----------------|    *
  1214. ;* |    Current            |<-frameptr| code base -> = n/a       |    *
  1215. ;* :    Stack            :    |--------+-----------------|    *
  1216. ;* |    Frame            |<-topofstack|return addr disp = na|    *
  1217. ;* |--------+-------------------|    |--------+-----------------|    *
  1218. ;* |    unused stack        |    | caller dynamic link = n/a|    *
  1219. ;* :                :    |--------+-----------------|    *
  1220. ;* :                :    | fluid env -> = FNV_reg   |    *
  1221. ;* |                |    |--------------------------|    *
  1222. ;* +--------+-------------------+    | prev stk seg -> = nil       |    *
  1223. ;* |--------+-------------------|                    *
  1224. ;* |    global env -> = GNV_reg |                    *
  1225. ;* |--------+-------------------|                    *
  1226. ;* |    Contents        |                    *
  1227. ;* :    of            :                    *
  1228. ;* :    Stack            :                    *
  1229. ;* |    (m BYTEs)        |                    *
  1230. ;* +--------+-------------------+                    *
  1231. ;*                                    *
  1232. ;* Notes: This routine handles both routine stack overflow, and stack    *
  1233. ;*    overflow which is signaled during the creation of a        *
  1234. ;*    full continuation because of a call/cc.    All of the        *
  1235. ;*    fields of the continuation object are filled in by this     *
  1236. ;*    routine, but they are meaningless and will never be        *
  1237. ;*    used in the case of simple stack overflow.            *
  1238. ;************************************************************************
  1239. PROC C    stk_ovfl FAR USES si di
  1240.     LOCAL    @@si:WORD, @@reg:REG
  1241.  
  1242.     mov    [@@si], si        ; saves caller si for continuation
  1243.  
  1244.     mov    cx, [frameptr]        ; load current frame pointer,
  1245.     cmp    cx, 0            ; length of stack contents zero?
  1246.     jg    @@newcontinuation
  1247.  
  1248.     mov    ax, [prev_reg.page]    ; copy previous continuation
  1249.     mov    dx, [prev_reg.disp]
  1250.     mov    [tmp_reg.page], ax
  1251.     mov    [tmp_reg.disp], dx
  1252.     lea    ax, [prev_reg]    ; load address of PREV_reg, tmp_reg
  1253.     call    copy_blk C, ax, [tmp_adr]
  1254.     jmp    @@ret
  1255.  
  1256. @@newcontinuation:
  1257.     add    cx, OFFSET (TYPE CONTDEF).data-SIZE POINTER
  1258.     mov    dx, CONTTYPE        ; load tag=CONTTYPE
  1259.     lea    bx, [@@reg]        ; load address of temporary result reg
  1260.     call    alloc_block C, bx, dx, cx
  1261.  
  1262.     mov    cx, [frameptr]        ; reload length of continuations stack data
  1263.     mov    bx, [@@reg.page]    ; load returned pointer to
  1264.     mov    di, [@@reg.disp]    ; continuation object
  1265.     ldpage    es, bx
  1266.  
  1267.     mov    al, SPECFIX*2
  1268.     mov    [(CONTDEF es:di).base.tag], al
  1269.     mov    [(CONTDEF es:di).retaddr.tag], al
  1270.     mov    [(CONTDEF es:di).dynlink.tag], al
  1271.  
  1272.     mov    al, [cb_reg.bpage]    ; define code base pointer
  1273.     mov    dx, [cb_reg.disp]
  1274.     mov    [(CONTDEF es:di).codeblk.page], al
  1275.     mov    [(CONTDEF es:di).codeblk.disp], dx
  1276.  
  1277.     neg    dx            ; subtract CB_disp from si
  1278.     add    dx, [@@si]        ; use contents of si for return addr disp
  1279.     mov    [(CONTDEF es:di).retaddr.val], dx
  1280.  
  1281.     mov    ax, [frameptr]        ; define dynamic link
  1282.     mov    [(CONTDEF es:di).dynlink.val], ax
  1283.  
  1284.     mov    ax, [base]        ; set continuation's stack base
  1285.     mov    [(CONTDEF es:di).base.val], ax
  1286.     add    ax, cx            ; compute new stack buffer base
  1287.     mov    [base], ax        ; base <- base + frameptr
  1288.  
  1289.     mov    al, [fnv_reg.bpage]    ; set fluid environment pointer
  1290.     mov    dx, [fnv_reg.disp]
  1291.     mov    [(CONTDEF es:di).fluid.page], al
  1292.     mov    [(CONTDEF es:di).fluid.disp], dx
  1293.  
  1294.     mov    al, [gnv_reg.bpage]    ; set global environment pointer
  1295.     mov    dx, [gnv_reg.disp]
  1296.     mov    [(CONTDEF es:di).globenv.page], al
  1297.     mov    [(CONTDEF es:di).globenv.disp], dx
  1298.  
  1299.     mov    ax, [prev_reg.page]    ; set previous stack segment pointer
  1300.     mov    dx, [prev_reg.disp]
  1301.     mov    [(CONTDEF es:di).stk.page], al
  1302.     mov    [(CONTDEF es:di).stk.disp], dx
  1303.  
  1304.     mov    [prev_reg.page], bx    ; make previous stack segment register
  1305.     mov    [prev_reg.disp], di    ; point to the new continuation object
  1306.  
  1307.     add    [WORD LOW stk_out], cx    ; record number of BYTEs transfered
  1308.     adc    [WORD HIGH stk_out], 0
  1309.  
  1310.     lea    si, [s_stack]        ; move stack data to continuation object in the heap
  1311.     add    di, OFFSET (TYPE CONTDEF).data ; adjust for continuation header info
  1312.     shr    cx, 1            ; convert BYTEs to WORDs
  1313.     rep    movsw
  1314.     adc    cx, 0            ; if cx was odd, put 1 in cx
  1315.     rep    movsb            ; copy remaining BYTE, if needed
  1316.  
  1317.     lea    si, [s_stack]        ; move data in current stack frame to top of stack buffer
  1318.     mov    di, si            ; di <- top of stack buffer (0)
  1319.     add    si, [frameptr]        ; si <- current stack frame
  1320.     push    ds
  1321.     pop    es
  1322.     mov    cx, [topofstack]    ; load current top of stack,
  1323.     sub    cx, [frameptr]        ; subtract BYTEs moved to heap,
  1324.     mov    [topofstack], cx
  1325.     add    cx, SIZE POINTER    ; compute BYTEs of stack to move up
  1326.     shr    cx, 1            ; convert BYTEs to WORDs
  1327.     rep    movsw
  1328.     adc    cx, 0
  1329.     rep    movsb            ; copy remaining BYTE, if needed
  1330.     mov    [frameptr], 0        ; current frame now at top of stack buffer
  1331. @@ret:
  1332.     ret
  1333. ENDP    stk_ovfl
  1334.  
  1335. ;************************************************************************
  1336. ;* Local support - stack underflow handler                *
  1337. ;*                                    *
  1338. ;* Purpose:    To restore segments of the stack, which previously have    *
  1339. ;*    been moved to the heap, back into the stack buffer.        *
  1340. ;*                                    *
  1341. ;* Description:    Previously saved stack segments (moved to the heap    *
  1342. ;*    as the result of a stack overflow or a call/cc) are        *
  1343. ;*    represented as continuation data objects.    When this    *
  1344. ;*    routine is called, a "stack underflow" has occurred        *
  1345. ;*    as an "EXIT" operation needs to access a stack frame        *
  1346. ;*    higher in the stack, so data fields with a call/cc        *
  1347. ;*    continuation are ignored.                    *
  1348. ;************************************************************************
  1349. PROC C    stk_unfl USES si di ds
  1350.     mov    bx, [prev_reg.page]
  1351.     mov    si, [prev_reg.disp]
  1352.     or    bx, bx            ; stack link nil?
  1353.     jz    @@underflow
  1354.  
  1355.     push    ds
  1356.     pop    es
  1357.     ldpage    ds, bx
  1358.  
  1359.     mov    ax, [(CONTDEF si).base.val]    ; update stack buffer's base
  1360.     mov    [es:base], ax
  1361.  
  1362.     mov    al, [(CONTDEF si).stk.page] ; update previous stack segment register
  1363.     mov    dx, [(CONTDEF si).stk.disp]
  1364.     mov    [es:prev_reg.bpage], al
  1365.     mov    [es:prev_reg.disp], dx
  1366.  
  1367.     mov    cx, [(CONTDEF si).len]
  1368.     sub    cx, OFFSET (TYPE CONTDEF).data ; adjust length for continuation header
  1369.     add    si, OFFSET (TYPE CONTDEF).data ; adjust OFFSET for continuation header
  1370.     lea    di, [s_stack]
  1371.     mov    dx, cx            ; compute new top of stack
  1372.     sub    dx, SIZE POINTER
  1373.     mov    [es:topofstack], dx
  1374.  
  1375.     add    [WORD LOW es:stk_in], cx; update count of BYTEs transfered
  1376.     adc    [WORD HIGH es:stk_in], 0
  1377.  
  1378.     shr    cx, 1
  1379.     cld
  1380.     rep    movsw
  1381.     adc    cx, 1
  1382.     rep    movsb
  1383.     ret
  1384.  
  1385. @@underflow:
  1386.     lea    bx, [@@msg]
  1387. DATASEG
  1388. @@msg    DB    "[VM INTERNAL ERROR] Stack underflow", LF, 0
  1389. CODESEG
  1390.     call    zprintf C, bx
  1391.     call    force_reset C
  1392. ENDP    stk_unfl
  1393.  
  1394. ;************************************************************************
  1395. ;* Local support - Create new stack frame                *
  1396. ;*                                    *
  1397. ;* Purpose:    To create and partially define a new stack frame prior    *
  1398. ;*    to a procedure call                        *
  1399. ;*                                    *
  1400. ;* Description:    This routine allocates space on the top of the stack    *
  1401. ;*    for a new stack frame and defines the following fields:     *
  1402. ;*                                    *
  1403. ;*    code base pointer <- CB                        *
  1404. ;*    return addr disp <- si (contents of reg)            *
  1405. ;*    dynamic link <- frameptr                    *
  1406. ;*    static link's tag <- fixnum                    *
  1407. ;*    heap env <- current heap env                    *
  1408. ;*    static link <- current static link                *
  1409. ;*    closure pointer <- nil (implies an open call)            *
  1410. ;*                                    *
  1411. ;* Input Parameters:                            *
  1412. ;*    TIPC register si - the VM's location pointer            *
  1413. ;*    CB_page,CB_disp - the VM's code base register            *
  1414. ;*    frameptr - the VM's current frame pointer            *
  1415. ;*    topofstack - the VM's top of stack pointer            *
  1416. ;*                                    *
  1417. ;* Output Parameters:                            *
  1418. ;*    TIPC register bx - pointer to new stack frame            *
  1419. ;*    (displacement in stack)                        *
  1420. ;*    topofstack - top of stack pointer updated for new stack length    *
  1421. ;*                                    *
  1422. ;* Variables Modified:    The following variables will be modified if    *
  1423. ;*    a stack overflow occurs during the push operation for        *
  1424. ;*    the new stack frame:                        *
  1425. ;*                                    *
  1426. ;*    frameptr - the VM's current frame pointer(logically unchanged)    *
  1427. ;*    base - the VM's stack buffer base                *
  1428. ;*    PREV_page,PREV_disp - the VM's previous stack segment reg    *
  1429. ;************************************************************************
  1430. PROC    new_sf    NEAR
  1431. @@retry:
  1432.     mov    ax, [topofstack]    ; load current top of stack pointer
  1433.     mov    bx, ax            ; and make a copy
  1434.     add    ax, SIZE STKFDEF
  1435.     cmp    ax, STKSIZE-SIZE POINTER
  1436.     jg    @@overflow
  1437.     mov    [topofstack], ax    ; update top of stack pointer
  1438.     add    bx, SIZE POINTER    ; compute pointer to new stack frame
  1439.  
  1440.     mov    al, SPECFIX*2
  1441.     mov    [s_stack+bx.retaddr.page], al
  1442.     mov    [s_stack+bx.dynlink.page], al
  1443.     mov    [s_stack+bx.statlink.page], al
  1444.  
  1445.     xor    ax, ax
  1446.     mov    [s_stack+bx.closure.page], al
  1447.     mov    [s_stack+bx.closure.disp], ax
  1448.  
  1449.     mov    al, [cb_reg.bpage]    ; move current code base pointer
  1450.     mov    dx, [cb_reg.disp]
  1451.     mov    [s_stack+bx.codeblk.page], al ; into the new stack frame
  1452.     mov    [s_stack+bx.codeblk.disp], dx
  1453.  
  1454.     sub    si, dx            ; compute ret addr relative to code block
  1455.     mov    [s_stack+bx.retaddr.disp], si
  1456.     add    si, dx
  1457.  
  1458.     mov    di, [frameptr]        ; load the current stack frame pointer
  1459.     mov    al, [s_stack+di.heap.page]
  1460.     mov    dx, [s_stack+di.heap.disp]
  1461.     mov    [s_stack+bx.heap.page], al
  1462.     mov    [s_stack+bx.heap.disp], dx
  1463.  
  1464.     mov    ax, [s_stack+di.statlink.disp]
  1465.     mov    [s_stack+bx.statlink.disp], ax
  1466.  
  1467.     add    di, [base]
  1468.     mov    [s_stack+bx.dynlink.disp], di
  1469.     ret
  1470.  
  1471. @@overflow:
  1472.     push    es            ; save es over C call
  1473.     call    stk_ovfl C        ; process the overflow
  1474.     pop    es
  1475.     jmp    @@retry
  1476. ENDP    new_sf
  1477.  
  1478. ;************************************************************************
  1479. ;* Local support - drop items from the heap environment            *
  1480. ;*                                    *
  1481. ;* Purpose:    To drop "n" items off the local heap environment    *
  1482. ;*                                    *
  1483. ;* Input Parameters:                            *
  1484. ;*    TIPC register cx - the number of items to drop            *
  1485. ;*    frameptr - the current stack frame pointer            *
  1486. ;*                                    *
  1487. ;* Output Parameters:                            *
  1488. ;*    TIPC register bx - page number for the remaining        *
  1489. ;*    heap environment list                        *
  1490. ;*    TIPC register di - displacement pointer for the            *
  1491. ;*    remaining heap environment                    *
  1492. ;*                                    *
  1493. ;* Registers/Variables Modified:                    *
  1494. ;*    cx - decremented to zero                    *
  1495. ;*    TIPC register es - contents undefined                *
  1496. ;************************************************************************
  1497. PROC    delta_hp    NEAR
  1498.     mov    di, [frameptr]
  1499.     xor    bx, bx
  1500.     mov    bl, [s_stack+di.heap.page]
  1501.     mov    di, [s_stack+di.heap.disp]
  1502.     or    cx, cx            ; drop zero elements?
  1503.     jle    @@ret
  1504. @@loop:
  1505.     ldpage    es, bx
  1506.     mov    bl, [(LISTDEF es:di).cdr.page]    ; load link pointer (cdr field)
  1507.     mov    di, [(LISTDEF es:di).cdr.disp]
  1508.     loop    @@loop
  1509. @@ret:
  1510.     ret
  1511. ENDP    delta_hp
  1512.  
  1513. ;************************************************************************
  1514. ;* Local support - Obtain Frame Pointer for given lexical level        *
  1515. ;*                                    *
  1516. ;* Input Parameters:                            *
  1517. ;*    TIPC register cx - desired lexical level number            *
  1518. ;*    0=current lexical level,                    *
  1519. ;*    1=lexical parent's level, etc.                    *
  1520. ;*    frameptr - current frame pointer                *
  1521. ;*    base - current stack buffer base                *
  1522. ;*                                    *
  1523. ;* Output Parameters:                            *
  1524. ;*    TIPC register bx - frame pointer for desired level        *
  1525. ;*    (absolute location in stack)                    *
  1526. ;*    es:[si] - pointer to desired stack frame            *
  1527. ;*    (either in stack buffer, or in the heap)            *
  1528. ;*                                    *
  1529. ;* Notes:    Register usage:                        *
  1530. ;*    ax - zeroed, so page numbers can be loaded into al        *
  1531. ;*    prior to copying to di                        *
  1532. ;*    bx - frame pointer for current level                *
  1533. ;*    cx - lexical level counter.    decremented at each level    *
  1534. ;*    dx - base OFFSET of the stack segment currently being        *
  1535. ;*    examined                            *
  1536. ;*    si - stack segment's (continuation's) displacement        *
  1537. ;*    di - temporarily hold page number of next stack segment     *
  1538. ;************************************************************************
  1539. PROC    delta_lv    NEAR
  1540.     mov    bx, [frameptr]
  1541.     mov    dx, [base]
  1542.     or    cx, cx
  1543.     jg    @@nothere
  1544.  
  1545.     lea    si, [s_stack+bx]    ; compute addr of current frame pointer
  1546.     add    bx, dx            ; adjust for base of stack buffer
  1547.     push    ds
  1548.     pop    es
  1549.     ret                ; return bx, [es:si] to caller
  1550.  
  1551. @@loop:
  1552.     sub    bx, dx            ; adjust absolute frame ptr by base
  1553.     jb    @@searchhigher
  1554. @@nothere:
  1555.     mov    bx, [s_stack+bx.statlink.disp]
  1556.     loop    @@loop            ; iterate until desired level found
  1557.  
  1558.     mov    si, bx            ; copy absolute frame pointer
  1559.     sub    si, dx            ; adjust for current stack buffer base
  1560.     jb    @@outofstack
  1561.     add    si, OFFSET s_stack    ; compute address of frame in stack buffer
  1562.     push    ds
  1563.     pop    es
  1564.     ret                ; return bx, [es:si]
  1565.  
  1566. @@outofstack:
  1567.     mov    di, [prev_reg.page]    ; load pointer to previous stack segment
  1568.     mov    si, [prev_reg.disp]
  1569.     ldpage    es, di
  1570.     mov    dx, [(CONTDEF es:si).base.val]
  1571.     xor    ax, ax
  1572. @@nextone:
  1573.     cmp    bx, dx            ; is frame within this segment?
  1574.     jae    @@here
  1575.     mov    al, [(CONTDEF es:si).stk.page] ; load pointer to its previous segment
  1576.     mov    di, ax
  1577.     mov    si, [(CONTDEF es:si).stk.disp]
  1578.     ldpage    es, di
  1579.     mov    dx, [(CONTDEF es:si).base.val]    ; load stack segment's base OFFSET
  1580.     jmp    @@nextone
  1581. @@here:
  1582.     mov    ax, bx            ; copy absolute frame pointer for level
  1583.     sub    ax, dx            ; subtract this stack segment's base
  1584.     add    si, ax            ; add to continuation OFFSET
  1585.     add    si, OFFSET (TYPE CONTDEF).data ; add fudge factor for continuation header
  1586.     ret                ; return bx, es:[si] to caller
  1587.  
  1588. @@searchhigher:
  1589.     add    bx, dx            ; compute absolute location in stack
  1590.     mov    di, [prev_reg.page]    ; load previous stack segment pointer
  1591.     mov    si, [prev_reg.disp]
  1592.     ldpage    es, di
  1593.     mov    dx, [(CONTDEF es:si).base.val]
  1594.     xor    ax, ax
  1595. @@searchnext:
  1596.     cmp    bx, dx            ; is frame in this stack segment?
  1597.     jae    @@found
  1598.     mov    al, [(CONTDEF es:si).stk.page]; fetch pointer to next previous segment
  1599.     mov    di, ax
  1600.     mov    si, [(CONTDEF es:si).stk.disp]
  1601.     ldpage    es, di
  1602.     mov    dx, [(CONTDEF es:si).base.val] ; load this segment's base OFFSET
  1603.     jmp    @@searchnext
  1604. @@found:
  1605.     sub    bx, dx            ; adjust frame displacement for seg base
  1606.     mov    bx, [(STKFDEF (CONTDEF es:si+bx).data).statlink.disp] ; load static link
  1607.     loop    @@searchnext
  1608.     jmp    @@nextone
  1609. ENDP    delta_lv
  1610.  
  1611. ;************************************************************************
  1612. ;* Local support - Expand "apply's" argument list into registers R1-Rn    *
  1613. ;*                                    *
  1614. ;* Purpose:    To expand the argument list of an "apply" so that the    *
  1615. ;*    operands are in the proper operand registers (R1-Rn)        *
  1616. ;*    for a call to a closed procedure.                *
  1617. ;*                                    *
  1618. ;* Input Parameters:    TIPC register ah - the number of the VM's    *
  1619. ;*    general register which contains the pointer to            *
  1620. ;*    the linked list of arguments.                    *
  1621. ;*                                    *
  1622. ;* Output Parameters:    TIPC register cx - a count of the arguments.    *
  1623. ;*                                    *
  1624. ;* Note:    The "apply" operation expects two operands which are a    *
  1625. ;*    function and a 'list' of arguments.    In the event that    *
  1626. ;*    the second argument is not a list, this routine simply        *
  1627. ;*    substitutes that value as if it were an argument.    This    *
  1628. ;*    means that the "LIST" function is not actually needed        *
  1629. ;*    for an argument list containing only one value.            *
  1630. ;*    For example, the following are handled equivalently:        *
  1631. ;*                                    *
  1632. ;*    "correct" code    "not-correct" code                *
  1633. ;*    (apply ftn (list 1))    (apply ftn 1)                *
  1634. ;*    (apply ftn (list a b))    (apply ftn (cons a b))            *
  1635. ;*                                    *
  1636. ;*    Although this could be viewed as an optimization, in        *
  1637. ;*    that it saves one list cell each time the argument list     *
  1638. ;*    is created, the real reason it is done is to provide        *
  1639. ;*    a fixup action when an error condition is detected.        *
  1640. ;************************************************************************
  1641. PROC    aply_arg NEAR
  1642.     xor    bx, bx            ; copy the register number of the
  1643.     mov    bl, ah            ; argument list to bx
  1644.     mov    si, [regs+bx.disp]    ; load the argument list pointer
  1645.     mov    bx, [regs+bx.page]
  1646.     lea    di, [reg1]
  1647.     xor    cx, cx            ; count the arguments
  1648. @@writeloop:
  1649.     cmp    bl, 0            ; is pointer nil?
  1650.     je    @@done
  1651.     inc    cx
  1652.     cmp    [ptype+bx], LISTTYPE    ; pointer to a list cell?
  1653.     jne    @@dottedlist
  1654.     cmp    cx, NUM_REGS - 2    ; allow R1-R61 proper regs, R62 is the tail
  1655.     jae    @@dottedlist        ; we're out of registers, so condense up
  1656.     ldpage    es, bx
  1657.     mov    al, [(LISTDEF es:si).car.page]
  1658.     mov    dx, [(LISTDEF es:si).car.disp]
  1659.     mov    [(REG di).bpage], al
  1660.     mov    [(REG di).disp], dx
  1661.     mov    bl, [(LISTDEF es:si).cdr.page]
  1662.     mov    si, [(LISTDEF es:si).cdr.disp]
  1663.     add    di, SIZE REG        ; increment next register's address
  1664.     jmp    @@writeloop
  1665.  
  1666. @@dottedlist:
  1667.     mov    [(REG di).page], bx
  1668.     mov    [(REG di).disp], si
  1669. @@done:
  1670.     ret
  1671. ENDP    aply_arg
  1672.  
  1673. ;************************************************************************
  1674. ;*    Borland C callable routine to force a Scheme VM call        *
  1675. ;*    Calling Sequence:    force_call(ret)                *
  1676. ;*    where:    int ret - the return address (relative to the        *
  1677. ;*    current code block)                        *
  1678. ;************************************************************************
  1679. PROC C    force_call FAR @@ret:WORD
  1680.     mov    si, [@@ret]
  1681.     call    new_sf            ; create a new stack frame
  1682.     mov    [frameptr], bx
  1683.     ret
  1684. ENDP    force_call
  1685.  
  1686.     END
  1687.